#ifndef __AES_H__
#define __AES_H__


#define  AES_align_size(a)  ((a) / 16 * 16)
#define  AES_pad_align_size(a)  ( ((a)  % 16) ? (((a)  >> 4)  + 1) * 16 : (a) )

struct aes_ctx
{
    int key_length;
    unsigned int buf[120];
};

extern "C"
{
	void gen_tabs (void);
	int aes_set_key(struct aes_ctx * ctx, const unsigned char *in_key, unsigned int key_len);
	void aes_encrypt(struct aes_ctx * ctx, unsigned char *out, const unsigned char *in);
	void aes_decrypt(struct aes_ctx * ctx, unsigned char *out, const unsigned char *in);
}

void calculate_md5_with_secret(const unsigned char *packet_buffer, unsigned int packet_size, 
	const unsigned char *secret, unsigned int secret_length, unsigned char *md5_out);

class c_aes
{

public:
	static void encrypt(boost::asio::streambuf &sbuf)
	{	
		ostream os(&sbuf);
		int length = sbuf.size();
		int align_length = AES_pad_align_size(length);

		for (int i = 0; i < align_length - length; i++ )
			os.put('\0');
		unsigned char* out = boost::asio::buffer_cast<unsigned char*>(sbuf.prepare(align_length));
		const unsigned char *in = boost::asio::buffer_cast<const unsigned char*>(sbuf.data());

		for (int loop = 0; loop < align_length / 16; loop++)
		{
			aes_encrypt(&default_aes.s_aes, out + loop * 16, in + loop * 16);
		}
		sbuf.consume(align_length);
		sbuf.commit(align_length);
	}
	static void decrypt(boost::asio::streambuf &sbuf)
	{
		int length = sbuf.size();
		int align_length = AES_align_size(length);

		unsigned char* out = boost::asio::buffer_cast<unsigned char*>(sbuf.prepare(align_length));
		const unsigned char *in = boost::asio::buffer_cast<const unsigned char*>(sbuf.data());

		for (int loop = 0; loop < align_length / 16; loop++)
		{
			aes_decrypt(&default_aes.s_aes, out + loop * 16, in + loop * 16);
		}
		sbuf.consume(length);
		sbuf.commit(align_length);
	}
	c_aes()
	{
		gen_tabs();
		if (aes_set_key(&s_aes,  (unsigned char*)AES_KEY , 16) != 0)
		{
			//Vdebug(DEBUG_MAIN, "[main process]can't set key : %s " , AES_KEY );
		}
	}
private:
	static c_aes default_aes;
	struct aes_ctx s_aes;
};


#endif